Linux i2c总线(1)

您所在的位置:网站首页 i2c linux Linux i2c总线(1)

Linux i2c总线(1)

2023-04-03 05:51| 来源: 网络整理| 查看: 265

0. I2C子系统总体框架

1. 概念

        I2C总线因为它极简单的硬件连接和通讯方式,在现在的很多设备上它是一种不可或缺的通讯总线。当用单片机直接操作I2C时,其实很简单,只要正确把握IIC的操作时序就可以了,但是在linux系统中,I2C子系统结构是稍微有一点复杂度的,因为它涉及到很多linux内核相关的知识。

        这里的I2C Bus并不是通讯上的总线,而是linux系统为了管理设备和驱动而虚拟出来的(注意这里的虚拟和平台总线的虚拟,意思上有区别),I2C Bus被用来挂载I2C适配器(adapter)和I2C设备(client)。

        平台总线和IIC总线在Linux下都是被虚拟成总线模块,但是两者有很大区别,平台总线是纯虚拟的总线,不是通讯上的物理总线;而IIC总线是通讯上的物理总线,是有具体的控制器的(即dapter)。

        I2C适配器是SoC中内置i2c控制器的软件抽象,可以理解为他所代表的是一个I2C主机。

2. 两种实现方法

        I2C子系统提供的两种驱动实现方法(源码中I2C相关的驱动均位于:drivers/i2c目录下)

        第一种叫i2c-dev,对应drivers/i2c/i2c-dev.c,这种方法只是封装了主机(I2C master,一般是SoC中内置的I2C 控制器)的I2C 基本操作,并且向应用层提供相应的操作接口,应用层代码需要自己去实现对slave 的控制和操作,所以这种I2C 驱动相当于只是提供给应用层可以访问slave 硬件设备的接口,本身并未对硬件做任何操作,应用需要实现对硬件的操作,因此写应用的人必须对硬件非常了解,所以这种I2C 驱动又叫做“应用层驱动”,这种方式并不主流,它的优势是把差异化都放在应用中,这样在设备比较难缠(尤其是slave是非标准I2C时)时不用动驱动,而只需要修改应用就可以实现对各种设备的驱动。

        第二种I2C 驱动是所有的代码都放在驱动层实现,直接向应用层提供最终结果。应用层甚至不需要知道这里面有I2C存在,譬如电容式触摸屏驱动,直接向应用层提供/dev/input/event1 的操作接口,应用层编程的人根本不知道event1 中涉及到了I2C。

3. 相关的结构体

(1)struct i2c_adapter(I2C适配器)

        struct i2c_adapter是用来描述一个I2C适配器,在SoC中的指的就是内部外设I2C控制器,当向I2C核心层注册一个I2C适配器时就需要提供这样的一个结构体变量。

struct i2c_adapter { struct module *owner; //所有者 unsigned int id; unsigned int class; //该适配器支持的从机设备的类型 const struct i2c_algorithm *algo; //该适配器与从机设备的通信算法 int timeout; //超时时间 struct device dev; //该适配器设备对应的device int nr; //适配器的编号 char name[48]; //适配器的名字 struct list_head userspace_clients; //用来挂接与适配器匹配成功的从机设备i2c_client的一个链表头 };

(2)struct i2c_algorithm(I2C算法)

        struct i2c_algorithm结构体代表的是适配器的通信算法,在构建i2c_adapter结构体变量的时候会去填充这个元素。

struct i2c_algorithm { int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); u32 (*functionality) (struct i2c_adapter *); };

        注意:smbus协议是从I2C协议的基础上发展而来的,他们之间有很大的相似度,SMBus与I2C总线之间在时序特性上存在一些差别。

(3)struct i2c_client(I2C设备)

struct i2c_client { //用来描述一个i2c 从机设备 unsigned short flags; //描述i2c 从机设备特性的标志位 unsigned short addr; //i2c 从机设备的地址 ······ char name[I2C_NAME_SIZE]; //i2c 从机设备的名字 struct i2c_adapter *adapter; //指向与从机设备匹配成功的适配器 struct i2c_driver *driver; //指向与从机设备匹配成功的设备驱动 struct device dev; //该从机设备对应的device int irq; //从机设备的中断引脚 struct list_head detected; //作为一个链表节点挂接到与他匹配成功的i2c_driver相应的链表头上 };

(4)struct device_driver(I2C设备驱动)

struct i2c_driver { //代表一个i2c设备驱动 unsigned int class; //i2c设备驱动所支持的i2c设备的类型 int (*attach_adapter)(struct i2c_adapter *); //用来匹配适配器的函数 adapter int (*detach_adapter)(struct i2c_adapter *); ······ int (*probe)(struct i2c_client *, const struct i2c_device_id *); //设备驱动层的probe函数 int (*remove)(struct i2c_client *); //设备驱动层卸载函数 struct device_driver driver; //该i2c设备驱动所对应的device_driver const struct i2c_device_id *id_table; //设备驱动层用来匹配设备的id_table const unsigned short *address_list; //该设备驱动支持的所有次设备的地址数组 struct list_head clients; //用来挂接与该i2c_driver匹配成功的i2c_client (从机设备)的一个链表头 }; struct i2c_board_info { //这个结构体是用来描述板子上的一个i2c从机设备的信息 char type[I2C_NAME_SIZE]; //i2c从机设备的名字,用来初始化i2c_client.name unsigned short flags; //用来初始化i2c_client.flags unsigned short addr; //用来初始化 i2c_client.addr void *platform_data; //用来初始化 i2c_client.dev.platform_data struct dev_archdata *archdata; //用来初始化i2c_client.dev.archdata #ifdef CONFIG_OF struct device_node *of_node; #endif int irq; //用来初始化i2c_client.irq }; struct i2c_devinfo { struct list_head list; //作为一个链表节点挂接到__i2c_board_list 链表上去 int busnum; //适配器的编号 struct i2c_board_info board_info; //内置的i2c_board_info 结构体 }; 4. 关键文件(drivers\i2c)

(1)i2c-core.c: i2c核心层

(2)busses目录:这个文件中是已经编写好的各种向i2c核心层注册的适配器

(3)algos目录:这个目录里面是一些I2C通信算法



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3